package com.yx.filesystem.storage;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

public final class Archive {
	public static final String FILE_SAVE_ROOT_PATH = getRootDir();
	public static final long NOW_TIME_STAMP = nowDateTime();// 20151011063542000000000001

	String[] nodeIdList;
	long timeStamp;
	long fileNumber;

	public Archive(Node node, long timeStamp, long fileNumber) {
		nodeIdList=new String[node.getBachupNodes().size()+1];
		nodeIdList[0]=node.getId();
		for(int i=0;i<node.getBachupNodes().size();i++){
			nodeIdList[i+1]=node.getBachupNodes().get(i).getId();
		}
		this.timeStamp = timeStamp;
		this.fileNumber = fileNumber;
	}
	public Archive(String nodeId, long timeStamp, long fileNumber) {
		nodeIdList=new String[1];
		nodeIdList[0]=nodeId;
		this.timeStamp = timeStamp;
		this.fileNumber = fileNumber;
	}

	public Archive(String fileName) throws Exception {
		int length=fileName.length();
		this.timeStamp = Long.parseLong(fileName.substring(length-26, length-12));
		this.fileNumber = Long.parseLong(fileName.substring(length-12, length));
		fileName = fileName.substring(0,length-26);
		length=fileName.length();
		nodeIdList=new String[length/5];
		for (int i = 0; i < nodeIdList.length; i++) {
			nodeIdList[i]=fileName.substring(5*i, 5*i+5);
		}
	}
	
	public String getName() {
		String fName ="";
		for (int i = 0; i < nodeIdList.length; i++) {
			fName = fName+nodeIdList[i];
		}
		return fName+getFileTotalNumber();
	}
	public String[] getNodeId(){
		return nodeIdList;
	}

	public BigInteger getFileTotalNumber() {
		String fileNumberStr = "" + fileNumber;
		while (fileNumberStr.length() < 12) {
			fileNumberStr = "0" + fileNumberStr;
		}
		return new BigInteger(timeStamp + fileNumberStr);
	}

	public String getPath() {
		String fileNumberStr = "" + fileNumber;
		while (fileNumberStr.length() < 12) {
			fileNumberStr = "0" + fileNumberStr;
		}
		int len = fileNumberStr.length();
		String fName = fileNumberStr.substring(len - 3, len) + ".dat";
		String dirName = fileNumberStr.substring(0, len - 6) + "/"
				+ fileNumberStr.substring(len - 6, len - 3);
		return FILE_SAVE_ROOT_PATH + "/" + nodeIdList[0] + "/" + timeStamp + "/"
				+ dirName + "/" + fName;
	}

	public long length() {
		File f = new File(getPath());
		if (f.exists()) {
			return f.length();
		}
		return 0;
	}

	public boolean exists() {
		File f = new File(getPath());
		return f.exists();
	}

	public boolean isBadFile() {
		File f = new File(getPath());
		if (f.canWrite()) {
			return true;
		}
		return false;
	}

	public void read(BufferedOutputStream socketOutput) throws Exception {
		FileInputStream file = null;
		BufferedInputStream fileInput=null;
		try {
			file = new FileInputStream(getPath());
			fileInput=new BufferedInputStream(file);
			byte[] buffer=new byte[SocketServer.BUFFER_SIZE];
			int size = 0;
			while ((size = fileInput.read(buffer)) != -1) {
				socketOutput.write(buffer,0,size);
				socketOutput.flush();
			}
		} catch (Exception e) {
			throw new Exception("读文件失败：" + e.getMessage());
		} finally {
			try {
				fileInput.close();
			} catch (Exception ex) {
			}			
			try {
				file.close();
			} catch (Exception ex) {
			}
		}
	}

	public void write(BufferedInputStream socketInput,long fileLength) throws Exception {
		BufferedOutputStream fileOut = null;
		FileOutputStream fileOutputStream = null;
		File file = null;
		try {
			file = new File(getPath());
			if (!file.getParentFile().exists()) {
				file.getParentFile().mkdirs();
			}
			if (file.exists())
				file.delete();
			fileOutputStream = new FileOutputStream(file, false);
			fileOut = new BufferedOutputStream(fileOutputStream);
			byte[] buffer = new byte[SocketServer.BUFFER_SIZE];
			long remain=fileLength;
			while (remain>0) {
				if(remain<SocketServer.BUFFER_SIZE)
					 buffer = new byte[Integer.parseInt(""+remain)];
				int size = socketInput.read(buffer);
				if (size > 0) {
					fileOut.write(buffer, 0, size);
					fileOut.flush();
					remain=remain-size;
				}
			}
		} catch (Exception e) {
			throw new Exception("存文件失败：" + e.getMessage());
		} finally {
			try {
				fileOut.close();
			} catch (Exception ex) {
			}
			try {
				fileOutputStream.close();
			} catch (Exception ex) {
			}
			try {
				file.setWritable(false);
			} catch (Exception ex) {
			}
		}
	}

	public static final List<String> getStorageSaveNodes() {
		List<String> nodes = new ArrayList<String>();
		String path = FILE_SAVE_ROOT_PATH + "/";
		File dir = new File(path);
		if (!dir.exists() || !dir.isDirectory())
			return nodes;
		File[] nodeDirs = dir.listFiles();
		for (File d : nodeDirs) {
			nodes.add(d.getName());
		}
		return nodes;
	}

	public static Archive getMaxArchive(String nodeId) {
		long[] timeStamps = getTimeStamps(nodeId);
		if (timeStamps.length == 0)
			return null;
		long maxFileNumber = getMaxFileNumber(nodeId,
				timeStamps[timeStamps.length - 1]);
		if (maxFileNumber < 0)
			return null;
		return new Archive(nodeId, timeStamps[timeStamps.length - 1], maxFileNumber);
	}

	public static final long[] getTimeStamps(String nodeId) {
		String nodeDirPath = FILE_SAVE_ROOT_PATH + "/" + nodeId + "/";
		File nodeDir = new File(nodeDirPath);
		if (!nodeDir.exists() || !nodeDir.isDirectory())
			return new long[0];
		File[] timeStampDirs = nodeDir.listFiles();
		long[] timeStamps = new long[timeStampDirs.length];
		for (int i = 0; i < timeStampDirs.length; i++) {
			timeStamps[i] = Long.parseLong(timeStampDirs[i].getName());
		}
		Arrays.sort(timeStamps);
		return timeStamps;
	}

	public static final long getMaxFileNumber(String nodeId, long timeStamp) {
		String path = FILE_SAVE_ROOT_PATH + "/" + nodeId + "/" + timeStamp
				+ "/";
		String fileNumberString = getMaxFileNumber(path);
		if (fileNumberString == null || "".equals(fileNumberString))
			return -1;
		return Long.parseLong(fileNumberString);
	}

	private static final String getMaxFileNumber(String path) {
		File dir = new File(path);
		if (!dir.exists())
			return "";
		int maxSubDirNumber = -1;
		String maxSubDirNumberStr = "";
		File[] subDirs = dir.listFiles();
		boolean isFile = false;
		for (File d : subDirs) {
			String name = d.getName();
			isFile = d.isFile();
			if (isFile)
				name = name.substring(0, name.indexOf("."));
			int dNumber = Integer.parseInt(name);
			if (dNumber > maxSubDirNumber) {
				maxSubDirNumber = dNumber;
				maxSubDirNumberStr = name;
			}
		}
		if (maxSubDirNumber == -1)
			return "";
		if (isFile)
			return maxSubDirNumberStr;
		String nextPath = path + maxSubDirNumberStr + "/";
		return "" + maxSubDirNumberStr + getMaxFileNumber(nextPath);
	}

	public long getTimeStamp() {
		return timeStamp;
	}

	public long getFileNumber() {
		return fileNumber;
	}

	private static String getRootDir() {
		File directory = new File("");
		return directory.getAbsolutePath() + "/data";
	}

	private static long nowDateTime() {
		SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
		try {
			Date now = new Date();
			String nowDateTime = formatter.format(now);
			return Long.parseLong(nowDateTime);
		} catch (Exception e) {
			return -1;
		}
	}
}
